package com.yunchao.maintenance.presentation.screen

import androidx.lifecycle.viewModelScope
import com.yunchao.feature.base.data.CustomAudioManager
import com.yunchao.feature.base.domain.result.andThen
import com.yunchao.feature.base.domain.result.createException
import com.yunchao.feature.base.domain.result.errorMsg
import com.yunchao.feature.base.presentation.viewmodel.BaseAction
import com.yunchao.feature.base.presentation.viewmodel.BaseEffect
import com.yunchao.feature.base.presentation.viewmodel.BaseState
import com.yunchao.feature.base.presentation.viewmodel.BaseViewModel
import com.yunchao.maintenance.domain.model.MaintenanceInfoModel
import com.yunchao.maintenance.domain.repository.MaintenanceInfoRepository
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.launch
import timber.log.Timber
import java.io.File

internal class MainViewModel(
    private val maintenanceInfoRepository: MaintenanceInfoRepository,
    private val customAudioManager: CustomAudioManager
) : BaseViewModel<MainViewModel.UiState, MainViewModel.Action, MainViewModel.UiEffect>(
    UiState.Idle
) {

    private var inventoryJob: Job? = null

    fun openDevice() = viewModelScope.launch {
        postSideEffect(UiEffect.ShowLoading)
        maintenanceInfoRepository.openDevice()
            .onFailure {
                postSideEffect(UiEffect.ShowToast(it.errorMsg)).apply {
                    customAudioManager.playSound(2)
                }
            }
            .onSuccess {
                postSideEffect(UiEffect.SuccessDialog("设备初始化成功")).apply {
                    customAudioManager.playSound(1)
                }
            }
    }

    fun closeDevice() = viewModelScope.launch {
        maintenanceInfoRepository.closeDevice()
    }

    fun inventoryAll(maintenanceInfoList: List<MaintenanceInfoModel>) {
        inventoryJob = viewModelScope.launch {
            maintenanceInfoRepository.inventoryAll(maintenanceInfoList.associateBy { it.lockNo })
                .flowOn(Dispatchers.IO)
                .collect {
                    sendAction(action = Action.GetMaintenanceInfoList(it)).apply {
                        customAudioManager.playSound(1)
                    }
                }
        }
    }

    fun stopInventory() {
        inventoryJob?.cancel()
        inventoryJob = null
    }

    fun inventoryOnce() = viewModelScope.launch {
        postSideEffect(UiEffect.ShowLoading)
        maintenanceInfoRepository.inventoryOnce()
            .andThen { lockNo ->
                maintenanceInfoRepository.getMaintenanceInfoByLockNo(lockNo).getOrNull()?.let {
                    Result.success(it)
                } ?: Result.failure(createException("锁号：${lockNo} 未登记"))
            }
            .onFailure {
                postSideEffect(UiEffect.ShowToast(it.errorMsg)).apply {
                    customAudioManager.playSound(2)
                }
            }
            .onSuccess {
                sendAction(action = Action.GetMaintenanceInfo(it)).apply {
                    postSideEffect(UiEffect.HideLoading)
                }.apply {
                    customAudioManager.playSound(1)
                }

            }
    }

    fun getMaintenanceFileList() = viewModelScope.launch {
        maintenanceInfoRepository.getMaintenanceFileList()
            .onSuccess {
                postSideEffect(UiEffect.FileList(it))
            }
            .onFailure {
                postSideEffect(UiEffect.ShowToast(it.errorMsg)).apply {
                    customAudioManager.playSound(2)
                }
            }
    }

    fun handleMaintenanceFile(fileName: String) = viewModelScope.launch {
        postSideEffect(UiEffect.ShowLoading)
        maintenanceInfoRepository.addMaintenanceInfoList(fileName)
            .onFailure {
                Timber.e(it)
                postSideEffect(UiEffect.ShowToast(it.errorMsg)).apply {
                    customAudioManager.playSound(2)
                }
            }
            .onSuccess {
                postSideEffect(UiEffect.SuccessDialog("数据导入成功")).apply {
                    customAudioManager.playSound(1)
                }
            }
    }

    fun getMaintenanceInfo(lockNo: String) = viewModelScope.launch {
        if (lockNo.isBlank()) {
            postSideEffect(UiEffect.ShowToast("锁号不能为空"))
            return@launch
        }
        postSideEffect(UiEffect.ShowLoading)
        maintenanceInfoRepository.getMaintenanceInfoByLockNo(lockNo)
            .onFailure {
                postSideEffect(UiEffect.ShowToast(it.errorMsg)).apply {
                    customAudioManager.playSound(2)
                }
            }
            .onSuccess { result ->
                result?.let {
                    sendAction(action = Action.GetMaintenanceInfo(it)).apply {
                        postSideEffect(UiEffect.HideLoading)
                    }.apply {
                        customAudioManager.playSound(1)
                    }
                } ?: sendAction(action = Action.GetMaintenanceInfo(null)).apply {
                    postSideEffect(UiEffect.ShowToast("锁号：${lockNo} 未登记"))
                }.apply {
                    customAudioManager.playSound(2)
                }

            }
    }

    override fun onCleared() {
        Timber.d("onCleared")
        closeDevice()
        super.onCleared()
    }

    fun saveDataToFile(models: List<MaintenanceInfoModel>) = viewModelScope.launch {
        if (models.isEmpty()) {
            postSideEffect(UiEffect.ShowToast("数据为空"))
            return@launch
        }
        postSideEffect(UiEffect.ShowLoading)

        maintenanceInfoRepository.writeDataToExcel(models)
            .onFailure {
                postSideEffect(UiEffect.ShowToast(it.errorMsg)).apply {
                    customAudioManager.playSound(2)
                }
            }
            .onSuccess { result ->
                postSideEffect(UiEffect.ShowToast(if (result) "数据导出成功" else "数据导出失败")).apply {
                    customAudioManager.playSound(if (result) 1 else 2)
                }
            }
    }

    internal sealed interface Action : BaseAction<UiState> {
        class GetMaintenanceInfo(private val data: MaintenanceInfoModel?) : Action {
            override fun reduce(state: UiState) = UiState.Content(data)
        }

        class GetMaintenanceInfoList(private val data: List<MaintenanceInfoModel>) : Action {
            override fun reduce(state: UiState) = UiState.ListData(data)
        }
    }

    internal sealed interface UiState : BaseState {
        data class Content(val data: MaintenanceInfoModel?) : UiState
        data class ListData(val list: List<MaintenanceInfoModel>) : UiState
        data object Idle : UiState
    }

    internal sealed interface UiEffect : BaseEffect {
        data object ShowLoading : UiEffect
        data object HideLoading : UiEffect
        data class SuccessDialog(val content: String) : UiEffect
        data class FileList(val list: List<File>) : UiEffect
        data class ShowToast(val msg: String) : UiEffect
    }
}